﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using RSPJ.Struct;
using RSPJ.Windows;
using RSPJ.Function;

namespace RSPJ.Function
{
    public class funcBandMath
    {
        int lines, samples;
        Stack<char> op;//符号栈
        Stack<string> num;//数字栈
        char ch, theta;
        string a, b;

        int i;

        List<double[,]> bandlist;

        public funcBandMath(List<double[,]> bandlist, int lines, int samples)
        {
            this.lines = lines;
            this.samples = samples;
            this.bandlist = bandlist;
        }

        //读入表达式并进行计算
        public double[,] Expression(char[] exp)
        {
            double[,] result = new double[lines, samples];

            op = new Stack<char>();
            num = new Stack<string>();
            op.Push('#'); // 标示运算结束
            List<char> tmp = new List<char>();

            i = 0;
            ch = exp[i++];
            while (ch != '#' || op.Peek() != '#')
            {
                if (!IsOperator(ch))
                {
                    tmp.Add(ch);
                    ch = exp[i++];
                }
                else
                {
                    if (tmp.Count != 0)
                    {
                        char[] t = new char[tmp.Count];
                        for (int p = 0; p < tmp.Count; p++)
                            t[p] = tmp[p];
                        string tmpnum = new string(t);
                        num.Push(tmpnum);
                        tmp.Clear();
                    }
                    switch (Precede(op.Peek(), ch))
                    {
                        case '<':
                            op.Push(ch);
                            ch = exp[i++];
                            break;
                        case '=':
                            op.Pop();
                            ch = exp[i++];
                            break;
                        case '>':
                            theta = op.Pop();
                            b = num.Pop();
                            a = num.Pop();
                            double an, bn;
                            int flag = 0;
                            if (double.TryParse(b, out bn))
                                flag += 2;
                            if (double.TryParse(a, out an))
                                flag += 1;
                            if (flag == 0)
                            {
                                int band2 = Int32.Parse(b.Replace("b", ""));
                                int band1 = Int32.Parse(a.Replace("b", ""));
                                double[,] tmpband = Operate(bandlist[band1 - 1], theta, bandlist[band2 - 1]);
                                bandlist.Add(tmpband);
                                num.Push("b" + bandlist.Count);
                            }
                            if (flag == 1)
                            {
                                int band = Int32.Parse(b.Replace("b", ""));
                                double[,] tmpband = Operate(an, theta, bandlist[band - 1]);
                                bandlist.Add(tmpband);
                                num.Push("b" + bandlist.Count);
                            }
                            if (flag == 2)
                            {
                                int band = Int32.Parse(a.Replace("b", ""));
                                double[,] tmpband = Operate(bandlist[band - 1], theta, bn);
                                bandlist.Add(tmpband);
                                num.Push("b" + bandlist.Count);
                            }
                            if (flag == 3)
                            {
                                num.Push(Convert.ToString(Operate(an, theta, bn)));
                            }
                            break;
                    }
                }
            }

            result = bandlist[bandlist.Count - 1];

            return result;
        }

        //进行计算
        private double[,] Operate(double[,] a, char theta, double[,] b)
        {
            double[,] result = new double[lines, samples];

            switch (theta)
            {
                case '+'://加法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a[i, j] + b[i, j];
                        }
                    }
                    break;
                case '-'://减法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a[i, j] - b[i, j];
                        }
                    }
                    break;
                case '*'://乘法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a[i, j] * b[i, j];
                        }
                    }
                    break;
                case '/'://除法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            if (b[i, j] == 0)
                                result[i, j] = 255;
                            else
                                result[i, j] = a[i, j] / b[i, j];
                        }
                    }
                    break;
                case '^'://指数幂
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = Math.Pow(a[i, j], b[i, j]);
                        }
                    }
                    break;
                case '%':
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            if (b[i, j] == 0)
                                result[i, j] = 255;
                            else
                                result[i, j] = a[i, j] % b[i, j];
                        }
                    }
                    break;
            }

            return result;
        }

        private double[,] Operate(double[,] a, char theta, double b)
        {
            double[,] result = new double[lines, samples];

            switch (theta)
            {
                case '+'://加法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a[i, j] + b;
                        }
                    }
                    break;
                case '-'://减法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a[i, j] - b;
                        }
                    }
                    break;
                case '*'://乘法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a[i, j] * b;
                        }
                    }
                    break;
                case '/'://除法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            if (b == 0)
                                result[i, j] = 255;
                            else
                                result[i, j] = a[i, j] / b;
                        }
                    }
                    break;
                case '^'://指数幂
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = Math.Pow(a[i, j], b);
                        }
                    }
                    break;
                case '%':
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            if (b == 0)
                                result[i, j] = 255;
                            else
                                result[i, j] = a[i, j] % b;
                        }
                    }
                    break;
            }

            return result;
        }

        private double[,] Operate(double a, char theta, double[,] b)
        {
            double[,] result = new double[lines, samples];

            switch (theta)
            {
                case '+'://加法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a + b[i, j];
                        }
                    }
                    break;
                case '-'://减法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a - b[i, j];
                        }
                    }
                    break;
                case '*'://乘法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = a * b[i, j];
                        }
                    }
                    break;
                case '/'://除法
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            if (b[i, j] == 0)
                                result[i, j] = 255;
                            else
                                result[i, j] = a / b[i, j];
                        }
                    }
                    break;
                case '^'://指数幂
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            result[i, j] = Math.Pow(a, b[i, j]);
                        }
                    }
                    break;
                case '%':
                    for (int i = 0; i < lines; i++)
                    {
                        for (int j = 0; j < samples; j++)
                        {
                            if (b[i, j] == 0)
                                result[i, j] = 255;
                            else
                                result[i, j] = a % b[i, j];
                        }
                    }
                    break;
            }

            return result;
        }

        private double Operate(double a, char theta, double b)
        {
            double[,] result = new double[lines, samples];

            switch (theta)
            {
                case '+'://加法
                    return a + b;
                case '-'://减法
                    return a - b;
                case '*'://乘法
                    return a * b;
                case '/'://除法
                    if (b == 0)
                        return 0;
                    else
                        return a / b;
                case '^'://指数幂
                    return Math.Pow(a, b);
                case '%':
                    if (b == 0)
                        return 0;
                    else
                        return a % b;
                default:
                    return 0;
            }
        }

        //判断是否为运算符
        private bool IsOperator(char c)
        {
            switch (c)
            {
                case '+':
                case '-':
                case '*':
                case '/':
                case '(':
                case ')':
                case '^':
                case '%':
                case '#':
                    return true;
                default:
                    return false;
            }
        }

        //判断运算符优先级
        private char Precede(char o1, char o2)
        {
            char f = 'e';
            switch (o2)
            {
                case '+':
                case '-':
                    if (o1 == '(' || o1 == '#')
                        f = '<';
                    else
                        f = '>';
                    break;
                case '*':
                case '/':
                case '%':
                    if (o1 == '+' || o1 == '-' || o1 == '(' || o1 == '#')
                        f = '<';
                    else
                        f = '>';
                    break;
                case '^':
                    if (o1 == '^' || o1 == ')')
                        f = '>';
                    else
                        f = '<';
                    break;
                case '(':
                    if (o1 == ')')
                    {
                        MessageBox.Show("括号匹配错误!");
                        f = 'e';
                    }
                    else
                        f = '<';
                    break;
                case ')':
                    switch (o1)
                    {
                        case '(':
                            f = '=';
                            break;
                        case '#':
                            MessageBox.Show("输入了错误的括号！");
                            f = 'e';
                            break;
                        default:
                            f = '>';
                            break;
                    }
                    break;
                case '#':
                    switch (o1)
                    {
                        case '#':
                            f = '=';
                            break;
                        case '(':
                            MessageBox.Show("表达式中有多余的括号！");
                            f = 'e';
                            break;
                        default:
                            f = '>';
                            break;
                    }
                    break;
            }
            return f;
        }
    }
}
